package org.ysling.litemall.db.service;
// Copyright (c) [ysling] [927069313@qq.com]
// [litemall-plus] is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//             http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
import com.github.pagehelper.PageHelper;
import org.springframework.util.StringUtils;
import org.ysling.litemall.db.dao.LitemallOrderMapper;
import org.ysling.litemall.db.domain.LitemallOrder;
import org.ysling.litemall.db.example.LitemallOrderExample;
import org.ysling.litemall.db.constant.OrderConstant;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
@CacheConfig(cacheNames = "order")
public class LitemallOrderService {

    @Resource
    private LitemallOrderMapper litemallOrderMapper;

    @CacheEvict(allEntries = true)
    public int add(LitemallOrder order) {
        order.setVersion(0);
        order.setAddTime(LocalDateTime.now());
        order.setUpdateTime(LocalDateTime.now());
        return litemallOrderMapper.insertSelective(order);
    }

    @Cacheable(sync = true)
    public int count(Integer userId) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andUserIdEqualTo(userId).andDeletedEqualTo(false);
        return (int) litemallOrderMapper.countByExample(example);
    }

    @Cacheable(sync = true)
    public LitemallOrder findById(Integer orderId) {
        return litemallOrderMapper.selectByPrimaryKey(orderId);
    }

    @Cacheable(sync = true)
    public LitemallOrder findById(Integer userId, Integer orderId) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andIdEqualTo(orderId).andUserIdEqualTo(userId).andDeletedEqualTo(false);
        return litemallOrderMapper.selectOneByExample(example);
    }

    @Cacheable(sync = true)
    public LitemallOrder findByBrandId(Integer brandId, Integer orderId) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andIdEqualTo(orderId).andBrandIdEqualTo(brandId).andDeletedEqualTo(false);
        return litemallOrderMapper.selectOneByExample(example);
    }

    public String generateOrderSn(Integer userId) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        LocalDateTime localDateTime = Instant.ofEpochMilli(System.currentTimeMillis()).atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
        String orderSn = df.format(localDateTime);
        while (countByOrderSn(userId, orderSn) != 0) {
            orderSn = df.format(localDateTime);
        }
        return orderSn;
    }

    @Cacheable(sync = true)
    public int countByOrderSn(Integer userId, String orderSn) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andUserIdEqualTo(userId).andOrderSnEqualTo(orderSn).andDeletedEqualTo(false);
        return (int) litemallOrderMapper.countByExample(example);
    }

    @Cacheable(sync = true)
    public List<LitemallOrder> queryByOrderStatus(Integer userId, List<Short> orderStatus, Integer page, Integer size, String sort, String order) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.setOrderByClause(LitemallOrder.Column.addTime.desc());
        LitemallOrderExample.Criteria criteria = example.or();
        criteria.andUserIdEqualTo(userId);
        criteria.andDeletedEqualTo(false);

        if (orderStatus != null) {
            criteria.andOrderStatusIn(orderStatus);
        }

        if (StringUtils.hasText(sort) && StringUtils.hasText(order)) {
            example.setOrderByClause(sort + " " + order);
        }

        PageHelper.startPage(page, size);
        return litemallOrderMapper.selectByExample(example);
    }

    @Cacheable(sync = true)
    public List<LitemallOrder> queryByBrandOrderStatus(Integer brandId, List<Short> orderStatus, Integer page, Integer size, String sort, String order) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.setOrderByClause(LitemallOrder.Column.addTime.desc());
        LitemallOrderExample.Criteria criteria = example.or();
        criteria.andBrandIdEqualTo(brandId);
        criteria.andDeletedEqualTo(false);

        if (orderStatus != null) {
            criteria.andOrderStatusIn(orderStatus);
        }

        if (StringUtils.hasText(sort) && StringUtils.hasText(order)) {
            example.setOrderByClause(sort + " " + order);
        }

        PageHelper.startPage(page, size);
        return litemallOrderMapper.selectByExample(example);
    }

    @Cacheable(sync = true)
    public List<LitemallOrder> querySelective(String mobile, String consignee,
                                              String orderSn, LocalDateTime start,
                                              LocalDateTime end, List<Short> orderStatusArray,
                                              Integer page, Integer size, String sort, String order) {
        LitemallOrderExample example = new LitemallOrderExample();
        LitemallOrderExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo(false);

        if(start != null){
            criteria.andAddTimeGreaterThanOrEqualTo(start);
        }
        if(end != null){
            criteria.andAddTimeLessThanOrEqualTo(end);
        }

        if (StringUtils.hasText(mobile)) {
            criteria.andMobileLike("%" + mobile + "%");
        }
        if (StringUtils.hasText(orderSn)) {
            criteria.andOrderSnLike("%" + orderSn + "%");
        }
        if (StringUtils.hasText(consignee)) {
            criteria.andConsigneeLike("%" + consignee + "%");
        }

        if (orderStatusArray != null && orderStatusArray.size() != 0) {
            criteria.andOrderStatusIn(orderStatusArray);
        }
        if (StringUtils.hasText(sort) && StringUtils.hasText(order)) {
            example.setOrderByClause(sort + " " + order);
        }

        PageHelper.startPage(page, size);
        return litemallOrderMapper.selectByExampleSelective(example);
    }

    @Cacheable(sync = true)
    public List<LitemallOrder> queryStatusArray(List<Short> orderStatusArray, Integer page, Integer size, String sort, String order) {
        LitemallOrderExample example = new LitemallOrderExample();
        LitemallOrderExample.Criteria criteria = example.createCriteria();

        if (orderStatusArray != null && orderStatusArray.size() != 0) {
            criteria.andOrderStatusIn(orderStatusArray);
        }
        criteria.andDeletedEqualTo(false);

        if (StringUtils.hasText(sort) && StringUtils.hasText(order)) {
            example.setOrderByClause(sort + " " + order);
        }

        PageHelper.startPage(page, size);
        return litemallOrderMapper.selectByExample(example);
    }

    @CacheEvict(allEntries = true)
    public int updateVersionSelective(LitemallOrder order) {
        order.setUpdateTime(LocalDateTime.now());
        return litemallOrderMapper.updateWithVersionByPrimaryKeySelective(order.getVersion(), order);
    }

    @CacheEvict(allEntries = true)
    public int updateSelective(LitemallOrder order) {
        order.setUpdateTime(LocalDateTime.now());
        return litemallOrderMapper.updateByPrimaryKeySelective(order);
    }

    @CacheEvict(allEntries = true)
    public void deleteById(Integer id) {
        litemallOrderMapper.logicalDeleteByPrimaryKey(id);
    }

    @Cacheable(sync = true)
    public int count() {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andDeletedEqualTo(false);
        return (int) litemallOrderMapper.countByExample(example);
    }

    @Cacheable(sync = true)
    public List<LitemallOrder> queryUnpaid() {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andOrderStatusEqualTo(OrderConstant.STATUS_CREATE).andDeletedEqualTo(false);
        return litemallOrderMapper.selectByExample(example);
    }

    @Cacheable(sync = true)
    public List<LitemallOrder> queryUnconfirm(int days) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime expired = now.minusDays(days);
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andOrderStatusEqualTo(OrderConstant.STATUS_SHIP).andShipTimeLessThan(expired).andDeletedEqualTo(false);
        return litemallOrderMapper.selectByExample(example);
    }

    @Cacheable(sync = true)
    public List<LitemallOrder> queryUnconfirmed() {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andOrderStatusEqualTo(OrderConstant.STATUS_SHIP).andDeletedEqualTo(false);
        return litemallOrderMapper.selectByExample(example);
    }

    @Cacheable(sync = true)
    public LitemallOrder findBySn(String orderSn) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andOrderSnEqualTo(orderSn).andDeletedEqualTo(false);
        return litemallOrderMapper.selectOneByExample(example);
    }

    @Cacheable(sync = true)
    public LitemallOrder findBySn(Integer userId, String orderSn) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andUserIdEqualTo(userId).andOrderSnEqualTo(orderSn).andDeletedEqualTo(false);
        return litemallOrderMapper.selectOneByExample(example);
    }

    @Cacheable(sync = true)
    public Map<Object, Object> orderInfo(Integer userId) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andUserIdEqualTo(userId).andDeletedEqualTo(false);
        List<LitemallOrder> orders = litemallOrderMapper.selectByExampleSelective(example, LitemallOrder.Column.orderStatus, LitemallOrder.Column.comments);

        int unpaid = 0;
        int unship = 0;
        int unrecv = 0;
        int uncomment = 0;
        for (LitemallOrder order : orders) {
            if (OrderConstant.isCreateStatus(order) || OrderConstant.isGrouponNoneStatus(order)) {
                unpaid++;
            } else if (OrderConstant.isPayStatus(order) || OrderConstant.isBtlPayStatus(order) || OrderConstant.isGrouponOnStatus(order)|| OrderConstant.isGrouponSucceedStatus(order)) {
                unship++;
            } else if (OrderConstant.isShipStatus(order)) {
                unrecv++;
            } else if (OrderConstant.isConfirmStatus(order) || OrderConstant.isAutoConfirmStatus(order)) {
                uncomment += order.getComments();
            } else {
                // do nothing
            }
        }
        
        Map<Object, Object> orderInfo = new HashMap<Object, Object>();
        orderInfo.put("unpaid", unpaid);
        orderInfo.put("unship", unship);
        orderInfo.put("unrecv", unrecv);
        orderInfo.put("uncomment", uncomment);
        return orderInfo;

    }

    @Cacheable(sync = true)
    public List<LitemallOrder> queryComment() {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andOrderStatusEqualTo(OrderConstant.STATUS_AUTO_CONFIRM).andCommentsGreaterThan((short) 0).andDeletedEqualTo(false);
        return litemallOrderMapper.selectByExample(example);
    }

    @CacheEvict(allEntries = true)
    public void updateAftersaleStatus(Integer orderId, Short statusReject) {
        LitemallOrder order = new LitemallOrder();
        order.setId(orderId);
        order.setAftersaleStatus(statusReject);
        order.setUpdateTime(LocalDateTime.now());
        litemallOrderMapper.updateByPrimaryKeySelective(order);
    }
}
